// *** LICENSE HEADER ***
// Filename: ./roster.cpp
// This file is part of Nodewarz 0.1
// Nodewarz is a 3d OpenGL strategy game
// Copyright (C) 2007 CZestmyr
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// *** END LICENSE HEADER ***
#include "roster.h"

roster::roster(engine* newParent) {
    parent = newParent;
    theButtons = new gui(newParent);

    theButtons->SetCallback(engine::GuiCallback);
    timeToSendPlayerData = _ROSTER_PLAYERDATA_TIME;

    lastPlayerNumber = 123456789;
}

roster::~roster(){
    delete theButtons;
}

void roster::Init(){
    waitingForResponse = false;
    connected = false;

    theButtons->Flush();
    theButtons->CreateButton(10, _HEIGHT - 50, 100, 40, "Back to menu", _BUTTON_BACKTOMENU);
    theButtons->CreateButton(_WIDTH - 110, _HEIGHT - 50, 100, 40, "Start game", _BUTTON_STARTGAME);
    theButtons->SetElementEnabled(false, _BUTTON_STARTGAME);
    theButtons->CreateLabel(10, _HEIGHT - 70, 14, "Please choose whether you want to create or join a game!", _BUTTON_MSGBAR);
    theButtons->CreateButton(10, 10, 100, 20, "Create game", _BUTTON_SERVERCLIENT);
    theButtons->CreateLabel(120, 10, 16, "Click to change between host/client");
    theButtons->CreateTextField(110, 70, 300, 18, "", 16, 32, _BUTTON_NAME);
    theButtons->CreateButton(420, 70, 100, 20, "Set nickname", _BUTTON_SENDNAME);
    theButtons->CreateLabel(10, 70, 15, "Your nickname:", _BUTTON_LABELS);
    theButtons->CreateLabel(530, 70, 16, parent->GetConnector()->GetLocalName(), _BUTTON_NICKLABEL);
    InitCreate();
}

void roster::InitJoin(){
    theButtons->CreateNumberField(10, 40, 30, 20, "127", 16, 255, 3, _BUTTON_IP1);
    theButtons->CreateLabel(44, 40, 16, ".", _BUTTON_IPDOT);
    theButtons->CreateNumberField(50, 40, 30, 20, "0", 16, 255, 3, _BUTTON_IP2);
    theButtons->CreateLabel(84, 40, 16, ".", _BUTTON_IPDOT);
    theButtons->CreateNumberField(90, 40, 30, 20, "0", 16, 255, 3, _BUTTON_IP3);
    theButtons->CreateLabel(124, 40, 16, ".", _BUTTON_IPDOT);
    theButtons->CreateNumberField(130, 40, 30, 20, "1", 16, 255, 3, _BUTTON_IP4);
    theButtons->CreateLabel(164, 40, 16, ":", _BUTTON_IPDOT);
    theButtons->CreateNumberField(170, 40, 45, 20, "6666", 16, 65535, 5, _BUTTON_IPPORT);
    theButtons->CreateButton(225, 40, 140, 20, "Connect to server", _BUTTON_CONNECT);
}

void roster::DeinitJoin(){
    theButtons->RemoveElement(_BUTTON_IP1);
    theButtons->RemoveElement(_BUTTON_IP2);
    theButtons->RemoveElement(_BUTTON_IP3);
    theButtons->RemoveElement(_BUTTON_IP4);
    theButtons->RemoveElement(_BUTTON_IPPORT);
    theButtons->RemoveElement(_BUTTON_IPDOT);
    theButtons->RemoveElement(_BUTTON_CONNECT);
}

void roster::InitCreate(){
    theButtons->CreateNumberField(10, 40, 45, 20, "6666", 16, 65535, 5, _BUTTON_IPPORT);
    theButtons->CreateButton(65, 40, 200, 20, "Create game on this UDP port", _BUTTON_CREATE);
}

void roster::DeinitCreate(){
    theButtons->RemoveElement(_BUTTON_IPPORT);
    theButtons->RemoveElement(_BUTTON_CREATE);
}

void roster::InitJoined(){
    theButtons->CreateLabel(_WIDTH/2, 90, 26, "Connected clients:", _BUTTON_JOINED_LABELS);
    theButtons->CreateLabel(_WIDTH/2, 120, 18, "Awaiting data...", _BUTTON_CLIENTLIST);
    theButtons->CreateLabel(_WIDTH/2 + 150, 120, 18, "Awaiting data...", _BUTTON_NAMELIST);
    theButtons->CreateLabel(10, 100, 16, "Player name", _BUTTON_JOINED_LABELS);
    theButtons->CreateLabel(110, 100, 16, "Color", _BUTTON_JOINED_LABELS);
    theButtons->CreateLabel(160, 100, 16, "Controlled by", _BUTTON_JOINED_LABELS);
    theButtons->CreateTextField(10, _HEIGHT - 200, _WIDTH - 130, 18, "", 16, 128, _BUTTON_MESSAGE_LINE);

    lastPlayerNumber = 123456789;
}

void roster::DeinitJoined(){
    theButtons->RemoveElement(_BUTTON_JOINED_LABELS);
    theButtons->RemoveElement(_BUTTON_CLIENTLIST);
    theButtons->RemoveElement(_BUTTON_NAMELIST);
    theButtons->RemoveElement(_BUTTON_MESSAGE_LINE);
    RemovePlayerGui();
}

void roster::InitCreated(){
    theButtons->CreateLabel(_WIDTH/2, 90, 26, "Connected clients:", _BUTTON_CREATED_LABELS);
    theButtons->CreateLabel(_WIDTH/2, 120, 18, "Awaiting data...", _BUTTON_CLIENTLIST);
    theButtons->CreateLabel(_WIDTH/2 + 150, 120, 18, "Awaiting data...", _BUTTON_NAMELIST);
    theButtons->CreateButton(10, 95, 80, 20, "Add player", _BUTTON_ADD_PLAYER);
    theButtons->CreateButton(100, 95, 110, 20, "Remove player", _BUTTON_DELETE_PLAYER);
    theButtons->SetElementEnabled(true, _BUTTON_STARTGAME);
    theButtons->CreateTextField(10, _HEIGHT - 200, _WIDTH - 130, 18, "", 16, 128, _BUTTON_MESSAGE_LINE);
    UpdatePlayers();
}

void roster::DeinitCreated(){
    theButtons->RemoveElement(_BUTTON_CREATED_LABELS);
    theButtons->RemoveElement(_BUTTON_CLIENTLIST);
    theButtons->RemoveElement(_BUTTON_NAMELIST);
    theButtons->RemoveElement(_BUTTON_ADD_PLAYER);
    theButtons->RemoveElement(_BUTTON_DELETE_PLAYER);
    theButtons->SetElementEnabled(false, _BUTTON_STARTGAME);
    theButtons->RemoveElement(_BUTTON_MESSAGE_LINE);
    RemovePlayerGui();
}

void roster::NewPlayerList() {
    thePlayerList = new playerList(parent->GetGame());
    thePlayerList->CreateDefaultPlayers();
    thePlayerList->SetConnector(parent->GetConnector());
}

void roster::DeletePlayerList() {
    delete thePlayerList;
}

playerList* roster::GetPlayerList() {
    return thePlayerList;
}

void roster::AddPlayer(){
    thePlayerList->IncPlayers();
    UpdatePlayers(true);
}

void roster::RemovePlayer(){
    thePlayerList->DecPlayers();
    UpdatePlayers(false);
}

void roster::UpdatePlayers(bool inc){
    if (!inc) {
        RemovePlayerGui(thePlayerList->GetPlayerNum());
    } else {
        RemovePlayerGui(thePlayerList->GetPlayerNum()-1);
        char helperBuffer[32];
        int i = thePlayerList->GetPlayerNum()-1;
        sprintf(helperBuffer, "Player %i", i+1);

        theButtons->CreateLabel(40, 120 + i*40, 16, helperBuffer, _BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_INGAMENAME);
        theButtons->CreateColorSelector(40, 140 + i*40, i, _BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_COLOR_SELECTOR);
        theButtons->CreateButton(120, 120 + i*40, 60, 20, "Change", _BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_CHANGE);
        theButtons->CreateLabel(190, 120 + i*40, 16, parent->GetConnector()->GetLocalName(), _BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_IP);
    }
}

void roster::UpdatePlayers(){
    RemovePlayerGui();

    char helperBuffer[32];
    for (int i = 0; i < thePlayerList->GetPlayerNum(); ++i) {
        sprintf(helperBuffer, "Player %i", i+1);

        theButtons->CreateLabel(40, 120 + i*40, 16, helperBuffer, _BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_INGAMENAME);
        theButtons->CreateColorSelector(40, 140 + i*40, i, _BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_COLOR_SELECTOR);
        theButtons->CreateButton(120, 120 + i*40, 60, 20, "Change", _BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_CHANGE);
        theButtons->CreateLabel(190, 120 + i*40, 16, parent->GetConnector()->GetLocalName(), _BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_IP);
    }
}

void roster::UpdatePlayerControls(){
    for (int i = 0; i < thePlayerList->GetPlayerNum(); ++i){
        player* pl = thePlayerList->GetPlayerPointer(i);
        parent->GetConnector()->UpdateClientNumber(pl);
    }
}

void roster::UpdateKickButtons(bool* clientArray){
    for (int i = 0; i < 4; ++i){
        theButtons->RemoveElement(_BUTTON_CLIENT_OFFSET + i);
    }
    int offset = 0;
    for (int i = 0; i < 4; ++i){
        if (clientArray[i]){
            theButtons->CreateButton(_WIDTH/2 - 50, 145 + offset*22, 40, 20, "Kick", _BUTTON_CLIENT_OFFSET + i);
            ++offset;
        }
    }
}

void roster::UpdatePlayerLabels(){
    if (!parent->GetConnector()->IsInit()) return;
    for (int i = 0; i < thePlayerList->GetPlayerNum(); ++i){
        if (thePlayerList->GetPlayerPointer(i)->GetType() == PT_LOCAL) {
            theButtons->SetElementText(parent->GetConnector()->GetLocalName(), _BUTTON_PLAYER_OFFSET + i*_BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_IP);
        } else {
            theButtons->SetElementText(parent->GetConnector()->GetClientName(thePlayerList->GetPlayerPointer(i)->GetClientNumber()), _BUTTON_PLAYER_OFFSET + i*_BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_IP);
        }
    }
}

void roster::UpdatePlayerColorData(){
    GLubyte red, green, blue;
    for (int i = 0; i < thePlayerList->GetPlayerNum(); ++i){
        ((colorselect*)theButtons->GetElement(_BUTTON_PLAYER_OFFSET + i*_BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_COLOR_SELECTOR))->GetColors(red, green, blue);
        thePlayerList->GetPlayerPointer(i)->SetColor(red, green, blue);
    }
}

void roster::ChangeMode(){
    if (waitingForResponse) return;

    if(parent->GetConnector()->IsServer()) {
        theButtons->SetElementText("Create game", _BUTTON_SERVERCLIENT);
        theButtons->SetElementText("Please specify the port on which to open a new game" , _BUTTON_MSGBAR);
        DeinitJoined();
        DeinitJoin();
        InitCreate();
    }
    else {
        theButtons->SetElementText("Join game", _BUTTON_SERVERCLIENT);
        theButtons->SetElementText("Please enter the game IP address and UDP port number" , _BUTTON_MSGBAR);
        DeinitCreated();
        DeinitCreate();
        InitJoin();
    }
}

void roster::Draw() {
    theButtons->Draw();
}

void roster::WaitForResponse(){
    waitingForResponse = true;
}

void roster::Update(int dt){
    if (waitingForResponse) {
        int response = parent->GetConnector()->IsConnected();
        switch (response){
            case 0:
                theButtons->SetElementText("Server full or does not exist" , _BUTTON_MSGBAR);
                InitJoin();
                waitingForResponse = false;
            break;
            case 1:
                theButtons->SetElementText("Connection to server successful" , _BUTTON_MSGBAR);
                InitJoined();
                //Little cheat to update player name on the server
                parent->GetConnector()->SetLocalName(parent->GetConnector()->GetLocalName());
                waitingForResponse = false;
                connected = true;
            break;
        }
    }

    if (connected) {
        //Check, whether we got disconnected
        if (parent->GetConnector()->IsConnected() == 0) {
            DeinitJoined();
            theButtons->SetElementText("You got kicked out of the game or the remote server quit", _BUTTON_MSGBAR);
            connected = false;
        }
    }

    if (parent->GetConnector()->IsInit() && parent->GetConnector()->IsServer()) {
        timeToSendPlayerData -= dt;
        if (timeToSendPlayerData <= 0) {
            timeToSendPlayerData = _ROSTER_PLAYERDATA_TIME;
            SendPlayerData();
        }
    }
}

void roster::SendPlayerData(){
    parent->GetConnector()->PrepareEvent(_CONNECTOR_EVENT_PLISTCHANGE);
    parent->GetConnector()->AppendEventDataI(thePlayerList->GetPlayerNum());
    parent->GetConnector()->SendEvent();

    for (int c = 0; c < 4; ++c){
        //For each client send it the correct info
        for (int p = 0; p < thePlayerList->GetPlayerNum(); ++p) {
            parent->GetConnector()->PrepareEvent(_CONNECTOR_EVENT_PDATA);
            parent->GetConnector()->AppendEventDataI(p);
            player* pl = thePlayerList->GetPlayerPointer(p);
            if (pl->GetType() == PT_REMOTE && pl->GetClientNumber() == c)
                parent->GetConnector()->AppendEventDataI(1);
            else
                parent->GetConnector()->AppendEventDataI(0);
            GLubyte r, g, b;
            ((colorselect*)theButtons->GetElement(_BUTTON_PLAYER_OFFSET + p*_BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_COLOR_SELECTOR))->GetColors(r,g,b);
            parent->GetConnector()->AppendEventDataI(r);
            parent->GetConnector()->AppendEventDataI(g);
            parent->GetConnector()->AppendEventDataI(b);
            if (pl->GetType() == PT_REMOTE)
                parent->GetConnector()->AppendEventDataS(parent->GetConnector()->GetClientName(pl->GetClientNumber()));
            else
                parent->GetConnector()->AppendEventDataS(parent->GetConnector()->GetLocalName());
            parent->GetConnector()->SendEventTo(c);
        }
    }
}

void roster::GenerateClientPlayerLabels(int playernum){
    if (playernum == lastPlayerNumber) return;

    RemovePlayerGui();

    char helperBuffer[32];

    for (int i = 0; i < playernum; ++i){
        sprintf(helperBuffer, "Player %i", i+1);
        theButtons->CreateLabel(10, 120 + i*20, 16, helperBuffer, _BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_INGAMENAME);
        theButtons->CreateColorViewer(110, 124 + i*20, 40, 16, _BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_COLOR_VIEWER);
        theButtons->CreateLabel(160, 120 + i*20, 16, "Awaiting data...", _BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_IP);
    }

    lastPlayerNumber = playernum;
}

void roster::SetClientPlayerData(int playernum, int control, int r, int g, int b, const char* str){
    if (control == 1) {
        theButtons->SetElementText("< YOU! >", _BUTTON_PLAYER_OFFSET + playernum * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_IP);
    }
    else
        theButtons->SetElementText(str, _BUTTON_PLAYER_OFFSET + playernum * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_IP);
        colorviewer* cv = (colorviewer*)theButtons->GetElement(_BUTTON_PLAYER_OFFSET + playernum * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_COLOR_VIEWER);
        if (cv) cv->SetColors(r, g, b);
}

void roster::SetClientPlayerList(){
    thePlayerList->DeletePlayers();
    thePlayerList->SetPlayerNum(lastPlayerNumber);
    for (int i = 0; i < lastPlayerNumber; ++i){
        player* pl = thePlayerList->GetPlayerPointer(i);
        if (!strcmp("< YOU! >", theButtons->GetElement(_BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_IP)->GetText())) {
            pl->SetType(PT_LOCAL);
        } else pl->SetType(PT_REMOTE);

        GLubyte r,g,b;
        ((colorviewer*)theButtons->GetElement(_BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_COLOR_VIEWER))->GetColors(r, g, b);
        pl->SetColor(r,g,b);
    }
}

gui* roster::GetGui(){
    return theButtons;
}

void roster::MouseClickEvent(int xCoordinate, int yCoordinate, bool right) {
    if (right) return;

    theButtons->Click(xCoordinate, yCoordinate);
}

void roster::MouseReleaseEvent(int xCoordinate, int yCoordinate, bool right) {
    if (right) return;

    theButtons->Release(xCoordinate, yCoordinate);
}

void roster::KeyPressEvent(SDLKey key, char c) {
    theButtons->KeyPress(key, c);
}

void roster::RemovePlayerGui(int num){
    //8 = maximum number of players
    for (int i = 0; i < 8; ++i){
        //Delete all the possible gui elements for each player
        if (num == i || num == -1){
            theButtons->RemoveElement(_BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_INGAMENAME);
            theButtons->RemoveElement(_BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_COLOR_SELECTOR);
            theButtons->RemoveElement(_BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_CHANGE);
            theButtons->RemoveElement(_BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_COLOR_VIEWER);
            theButtons->RemoveElement(_BUTTON_PLAYER_OFFSET + i * _BUTTON_PLAYER_LENGTH + _BUTTON_PLAYER_IP);
        }
    }
}
